package com.cmcc.shared.utils

import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.util.Base64

import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.ObjectInputStream
import java.io.ObjectOutputStream
import java.io.Serializable

object SpHelper {
    /**
     * Shared preference default name
     */
    private const val FILE_NAME = "USER_SETTING"

    /**
     * Save value to default shared preference file
     * @param con Application Context
     * @param key Value key
     * @param value Value(Type is simple type, such as String,Integer,Boolean,int,boolean and so on)
     */
    fun setParam(con: Context, key: String, value: Any) {
        setParam(con, FILE_NAME, key, value)
    }

    /**
     * Get value from default shared preference file
     * @param context Application Context
     * @param key Value key
     * @param defaultValue default value when key can not find.
     * @param <T> Value type
     * @return Value
    </T> */
    fun <T : Any> getParam(context: Context, key: String, defaultValue: T): T {
        return getParam(context, FILE_NAME, key, defaultValue)
    }

    /**
     * Save value to shared preference file
     * @param context Application Context
     * @param spName shared preference file name
     * @param key Value key
     * @param value Value(Type is simple type, such as String,Integer,Boolean,int,boolean and so on)
     */
    fun setParam(context: Context, spName: String, key: String, value: Any) {

        val type = value.javaClass.simpleName
        val sp = context.getSharedPreferences(spName, Context.MODE_PRIVATE)
        val editor = sp.edit()

        when (type) {
            "String" -> editor.putString(key, value as String)
            "Integer" -> editor.putInt(key, value as Int)
            "Boolean" -> editor.putBoolean(key, value as Boolean)
            "Float" -> editor.putFloat(key, value as Float)
            "Long" -> editor.putLong(key, value as Long)
        }
        editor.apply()
    }

    fun <T : Any> getParam(context: Context?, spName: String, key: String, defaultObject: T): T {
        val type = defaultObject.javaClass.simpleName
        if (context == null) return "" as T
        val sp = context.getSharedPreferences(spName, Context.MODE_PRIVATE)
        return when (type) {
            "String" -> sp.getString(key, defaultObject as String) as T
            "Integer" -> sp.getInt(key, defaultObject as Int) as T
            "Boolean" -> sp.getBoolean(key, defaultObject as Boolean) as T
            "Float" -> sp.getFloat(key, defaultObject as Float) as T
            "Long" -> sp.getLong(key, defaultObject as Long) as T
            else -> "" as T
        }

    }

    fun <T : Serializable> saveObject(context: Context, key: String, `object`: T) {
        saveObject(context, FILE_NAME, key, `object`)
    }

    fun <T : Serializable> getObject(context: Context, key: String): T? {
        return getObject(context, FILE_NAME, key)
    }


    fun <T : Serializable> saveList(context: Context, key: String, `object`: List<T>) {
        saveList(context, FILE_NAME, key, `object`)
    }

    fun <T : Serializable> getList(context: Context, key: String): List<T>? {
        return getList(context, FILE_NAME, key)
    }

    fun saveBitmap(context: Context, key: String, bitmap: Bitmap) {
        saveBitmap(context, FILE_NAME, key, bitmap)
    }

    fun getBitmap(context: Context, key: String): Bitmap? {
        return getBitmap(context, FILE_NAME, key)
    }

    fun saveBitmap(context: Context, fileName: String, key: String, bitmap: Bitmap) {
        try {
            val baos = ByteArrayOutputStream()
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
            val oAuthBase64 = String(Base64.encode(baos
                    .toByteArray(), Base64.DEFAULT))
            setParam(context, fileName, key, oAuthBase64)
            baos.close()
        } catch (e: Exception) {
            e.printStackTrace()
        }

    }


    fun getBitmap(context: Context, fileName: String, key: String): Bitmap? {
        val productBase64 = getParam(context, fileName, key, "")
        try {
            if (productBase64 == null) return null
            val base64 = Base64.decode(productBase64.toByteArray(), Base64.DEFAULT)
            val bais = ByteArrayInputStream(base64)
            val bitmap = BitmapFactory.decodeStream(bais)
            bais.close()
            return bitmap
        } catch (e: Exception) {
            return null
        }

    }

    fun <T : Serializable> saveList(context: Context, name: String, key: String, `object`: List<T>) {
        val baos = ByteArrayOutputStream()
        try {
            val oos = ObjectOutputStream(baos)
            oos.writeObject(`object`)
            val oAuth_Base64 = String(Base64.encode(baos
                    .toByteArray(), Base64.DEFAULT))
            setParam(context, name, key, oAuth_Base64)
            oos.close()
            baos.close()
        } catch (e: Exception) {
            e.printStackTrace()
        }

    }

    fun <T : Serializable> getList(context: Context, name: String, key: String): List<T>? {
        val productBase64 = getParam(context, name, key, "")
        try {
            if (productBase64 == null) return null
            val base64 = Base64.decode(productBase64.toByteArray(), Base64.DEFAULT)
            val bais = ByteArrayInputStream(base64)
            val bis = ObjectInputStream(bais)

            return bis.readObject() as List<T>

        } catch (e: Exception) {
            return null
        }

    }

    /**
     * Save Object which extends Serializable to shared preference file.
     * The method used default Base64 to encode object.
     * @param context Application Context
     * @param fileName shared preference file name
     * @param key key for object to locate
     * @param object object value
     * @param <T> object value type
    </T> */
    fun <T : Serializable> saveObject(context: Context, fileName: String, key: String, `object`: T) {
        val baos = ByteArrayOutputStream()
        try {
            val oos = ObjectOutputStream(baos)
            oos.writeObject(`object`)
            val oAuth_Base64 = String(Base64.encode(baos
                    .toByteArray(), Base64.DEFAULT))
            setParam(context, fileName, key, oAuth_Base64)

        } catch (e: Exception) {
            e.printStackTrace()
        }

    }

    fun <T : Serializable> getObject(context: Context, name: String, key: String): T? {
        val productBase64 = getParam(context, name, key, "")
        try {
            if (productBase64 == null) return null
            val base64 = Base64.decode(productBase64.toByteArray(), Base64.DEFAULT)
            val bais = ByteArrayInputStream(base64)
            val bis = ObjectInputStream(bais)

            return bis.readObject() as T

        } catch (e: Exception) {
            return null
        }

    }

    fun removeKey(context: Context, key: String) {
        removeKey(context, FILE_NAME, key)
    }

    /**
     * Remove key from default shared preference file.
     * @param context Application Context
     * @param key Key should remove from shared preference file
     */
    fun removeKey(context: Context, spName: String, key: String) {
        val sp = context.getSharedPreferences(spName, Context.MODE_PRIVATE)
        val editor = sp.edit()
        editor.remove(key)
        editor.apply()
    }


    fun removeAll(context:Context):Boolean{
        val sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE)
        val editor = sp.edit()
        editor.clear()
        return editor.commit()
    }
}